package com.zhu.tool_test.starke.util.weapons;

import lombok.Data;

import java.util.*;

/**
 * @author 4everlynn
 * @version V1.0
 * @description
 * @date 2019-07-03
 */
public class StarkeWeapons {

    @Data
    public static class EachForContext<V> {
        public V result;
        public Integer command;

        public void continueProcess() {
            this.command = EachForProcess.CONTROL_CONTINUE;
        }

        public void breakProcess() {
            this.command = EachForProcess.CONTROL_BREAK;
        }

        public void noneResult() {
            this.command = EachForProcess.CONTROL_NONE;
        }
    }

    public static class EachForProcess {
        public static Integer CONTROL_CONTINUE = 0x11;
        public static Integer CONTROL_BREAK = 0x12;
        public static Integer CONTROL_NONE = 0x13;


        public interface EntryProcess<K, T, V> {
            /**
             * process data
             *
             * @return after process value
             */
            public EachForContext<V> process(K key, T item, Integer index, EachForContext<V> context);
        }

        public interface ArrayProcess<T, V> {
            /**
             * process data
             *
             * @return after process value
             */
            public EachForContext<V> process(T item, Integer index, EachForContext<V> context);
        }
    }

    public static <T, V> Optional<V> each4(Set<T> targetArray, EachForProcess.ArrayProcess<T, V> arrayProcess, Class<V> resultClass) {
        return each4(new ArrayList<>(targetArray), arrayProcess, resultClass);
    }


    public static <T, V> Optional<V> each4(T[] targetArray, EachForProcess.ArrayProcess<T, V> arrayProcess, Class<V> resultClass) {
        return each4(new ArrayList<>(Arrays.asList(targetArray)), arrayProcess, resultClass);
    }


    public static <T, V> void each4(Set<T> targetArray, EachForProcess.ArrayProcess<T, V> arrayProcess) {
        each4(new ArrayList<>(targetArray), arrayProcess, null);
    }

    public static <T, V> void each4(T[] targetArray, EachForProcess.ArrayProcess<T, V> arrayProcess) {
        each4(targetArray, arrayProcess, null);
    }

    public static <T, V> void each4(List<T> targetArray, EachForProcess.ArrayProcess<T, V> arrayProcess) {
        each4(targetArray, arrayProcess, null);
    }

    @SuppressWarnings("Duplicates")
    public static <T, V> Optional<V> each4(List<T> targetArray, EachForProcess.ArrayProcess<T, V> arrayProcess, Class<V> resultClass) {
        if (null == arrayProcess) {
            return Optional.empty();
        }
        EachForContext<V> context = new EachForContext<>();
        for (int i = 0; i < targetArray.size(); i++) {
            EachForContext<V> process = arrayProcess.process(targetArray.get(i), i, context);
            if (null != process) {
                if (null != process.getResult() && null != resultClass) {
                    return Optional.of(process.getResult());
                }

                if (EachForProcess.CONTROL_NONE.equals(process.getCommand())) {
                    return Optional.empty();
                }
                if (null != context.getCommand()) {
                    if (EachForProcess.CONTROL_CONTINUE.equals(process.getCommand())) {
                        continue;
                    }
                    if (EachForProcess.CONTROL_BREAK.equals(process.getCommand())) {
                        break;
                    }
                    context.setCommand(null);
                }
            }
        }
        return Optional.empty();
    }

    @SuppressWarnings("Duplicates")
    public static <K, T, V> Optional<V> each4(Map<K, T> targetMap, EachForProcess.EntryProcess<K, T, V> arrayProcess, Class<V> resultClass) {
        if (null == arrayProcess) {
            return Optional.empty();
        }
        EachForContext<V> context = new EachForContext<>();
        Integer counter = 0;
        for (Map.Entry<K, T> entry : targetMap.entrySet()) {
            EachForContext<V> process = arrayProcess.process(entry.getKey(), entry.getValue(), counter++, context);
            if (null != process) {
                if (null != process.getResult() && null != resultClass) {
                    return Optional.of(process.getResult());
                }

                if (EachForProcess.CONTROL_NONE.equals(process.getCommand())) {
                    return Optional.empty();
                }
                if (null != context.getCommand()) {
                    if (EachForProcess.CONTROL_CONTINUE.equals(process.getCommand())) {
                        continue;
                    }
                    if (EachForProcess.CONTROL_BREAK.equals(process.getCommand())) {
                        break;
                    }
                    context.setCommand(null);
                }
            }
        }

        return Optional.empty();
    }

    public static <K, T, V> void each4(Map<K, T> targetMap, EachForProcess.EntryProcess<K, T, V> entryProcess) {
        each4(targetMap, entryProcess, null);
    }


}
